﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using C5;

namespace Gaur
{
    public class Regex
    {
        protected C5.ArrayList<Regex> sequence = new ArrayList<Regex>();

        public Regex()
        {
            
        }

        public Regex(Regex r)
        {
            if (r is Alt || r is Star)
            {
                this.sequence.Add(r);
            }
            else
            {
                foreach (var regex in r.sequence)
                {
                    this.sequence.Add(regex);
                }
            }
        }

        public Regex(string str)
        {
            this.Add(new Sym(str));
        }

        public void Add(Regex r)
        {
            if (r is Alt || r is Star)
            {
                this.sequence.Add(r);
            }
            else
            {
                foreach (var regex in r.sequence)
                {
                    this.sequence.Add(regex);
                }                
            }
        }

        public void Add(Sym sym)
        {
            this.sequence.Add(sym);
        }

        public static Regex operator +(Regex r1, Regex r2)
        {
            Regex res = new Regex();

            res.sequence.Add(r1);
            res.sequence.Add(r2);

            return res;
        }

        public static Star operator ~(Regex r)
        {
            return new Star(r);
        }

        public override string ToString()
        {
            string res = "";

            if (this.sequence.Count > 0)
            {
                res += this.sequence[0].ToString();

                if (this.sequence.Count > 1)
                {
                    for (int i = 1; i < this.sequence.Count; i++)
                    {
                        res += " " + this.sequence[i].ToString();
                    }
                }
            }

            return res;
        }

        public static Alt operator |(Regex r1, Regex r2)
        {
            if (r1 == null || r2 == null)
            {
                throw new ArgumentNullException("r1 | r2");
            }
            else
            {
                /*
                Alt ret = new Alt(r1);
                ret.Add(r2);
                return ret;
                */
                Alt res = new Alt();

                res.sequence.Add(r1);
                res.sequence.Add(r2);

                return res;
            }
        }
    }

    public class Eps : Regex
    {
        public override string ToString()
        {
            return "";
        }
    }

    public class Sym : Regex
    {
        private string sym;

        public Sym(string sym)
        {
            this.sym = sym;
        }

        public override string ToString()
        {
            return this.sym;
        }
    }

    public class Alt : Regex
    {
        public Alt() : base()
        {

        }

        public Alt(Regex r): base(r)
        {
        }

        public override string ToString()
        {
            string res = "";

            if (this.sequence.Count > 0)
            {
                res = "(" + this.sequence[0].ToString();

                for (int i = 1; i < this.sequence.Count; i++)
                {
                    res += " | " + this.sequence[i].ToString();
                }

                res += ")";
            }

            return res;
        }
    }

    public class Star : Regex
    {
        public Star(string str) : base(str)
        {

        }

        public Star(Regex r) : base(r)
        {

        }

        public override string ToString()
        {
            string res = "";

            if (this.sequence.Count > 0)
            {
                res += this.sequence[0].ToString();

                if (this.sequence.Count > 1)
                {
                    res = "(" + res;
                    for (int i = 1; i < this.sequence.Count; i++)
                    {
                        res += " " + this.sequence[i].ToString();
                    }
                    res += ")";
                }

                res += "*";
            }

            return res;
        }        
    }
}
